package com.etonenet.base;

import java.util.List;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.authentication.DefaultAuthenticationEventPublisher;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.provisioning.JdbcUserDetailsManager;

import com.etonenet.base.controller.UserDetailController;
import com.etonenet.base.entity.Resource;
import com.etonenet.base.entity.ResourceRole;
import com.etonenet.base.repository.ResourceRepository;
import com.etonenet.base.service.UserInfoService;

/**
 * spring security配置文件
 * 
 * @author wxu
 *
 */
@Configuration
@ComponentScan(basePackageClasses = { UserDetailController.class }, //
		basePackages = { "com.etonenet.base.service", "com.etonenet.base.test" })
@Import(value = { JpaConfig.class, SessionConfiguration.class })
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	public static final String AUTHORITY_ABC = "ROLE_ABC";

	@Autowired
	private DataSource dataSource;
	@Autowired
	private DefaultAuthenticationEventPublisher eventPublisher;
	@Autowired
	public UserInfoService userInfoService;

	public JdbcUserDetailsManager userDetailsManager() {
		JdbcUserDetailsManager manager = new JdbcUserDetailsManager();
		manager.setDataSource(dataSource);
		// 启用用户组功能
		manager.setEnableGroups(true);

		// 设置角色名称前缀为空
		manager.setRolePrefix("");

		return manager;
	}

	@Bean
	@Autowired
	public DefaultAuthenticationEventPublisher eventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		return new DefaultAuthenticationEventPublisher(applicationEventPublisher);
	}

	/**
	 * 
	 * @param auth
	 *            自动装载默认配置(@Autowired)
	 * @throws Exception
	 */
	@Autowired
	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		// @formatter:off
		auth
		.authenticationEventPublisher(eventPublisher) 	// 设定eventPublisher；默认为null，不发送事件
		.userDetailsService(userInfoService)			// 使用自定义的userdetails，扩展lockUser功能
		;
		// @formatter:on

		// FIXME METHOD 资源扩展
		// FIXME url 资源扩展
		super.configure(auth);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		// @formatter:off
		
		// session
		http
		.sessionManagement()
		.maximumSessions(1)				// 最大session数量
		.expiredUrl("/login") 			// 过期跳转页面
		.maxSessionsPreventsLogin(false) // 后面的用户禁止登陆
		;
		
		urlRegistry(http.authorizeRequests())
		.anyRequest().authenticated()
		
		.and()
		.formLogin()
//		.loginPage("/login")	// 自定义登陆页面
		.permitAll()
//		
//		.and().logout().logoutSuccessUrl("/").permitAll()
		
		
		.and()
		.csrf().disable()
		;
		// @formatter:on
	}

	@Autowired
	private ResourceRepository resourceRepository;

	/**
	 * 从数据库读取认证信息
	 * <p>
	 * 
	 * 此方法只在初始化时，加载；
	 * 
	 * @param authorizeRequests
	 * @return
	 * 
	 */
	private ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry urlRegistry(
			ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests) {
		List<Resource> resources = resourceRepository.findAll();

		// 设置认证信息
		for (Resource resource : resources) {
			List<ResourceRole> resourceRoles = resource.getResourceRoles();
			if (resourceRoles.isEmpty()) {
				continue;
			}

			String[] authorites = new String[resourceRoles.size()];
			for (int i = 0; i < authorites.length; i++) {
				authorites[i] = resourceRoles.get(i).getRole();
			}

			authorizeRequests.antMatchers(resource.getResString()).hasAnyAuthority(authorites);
		}

		return authorizeRequests;
	}

}
